package com.choudou5.solr.web;

import com.choudou5.solr.api.ApiConfig;
import com.choudou5.solr.bean.client.SolrClientAuth;
import com.choudou5.solr.framework.constants.ErrorResp;
import com.choudou5.solr.framework.util.PageJumpUtil;
import com.choudou5.solr.framework.util.RequestUtil;
import com.choudou5.solr.framework.util.SysSecurityUtil;
import com.choudou5.solr.service.ServiceHelper;
import com.choudou5.solr.service.client.SolrClientAuthService;
import com.choudou5.solr.util.IpUtil;
import com.choudou5.solr.util.LogDeBugUtil;
import com.choudou5.solr.util.StrUtil;
import com.choudou5.solr.utils.SysExceptionUtil;
import com.choudou5.solr.web.handler.ApiHandlerHelper;
import com.choudou5.solr.web.handler.BaseHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Name：API Servlet
 * @@author choudou5
 * @@date 2018-07-14
 */
public class ApiServlet extends AbsBaseServlet {

    private SolrClientAuthService clientAuthService = ServiceHelper.singleton(SolrClientAuthService.class);

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        handler(req, resp, "GET");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        handler(req, resp, "POST");
    }

    private void handler(HttpServletRequest req, HttpServletResponse resp, String method) throws ServletException, IOException {
        logger.info("into ApiServlet ....");
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        printlnJVMInfo(req); //打印jvm信息

        //检查安全访问（屏蔽黑名单IP）
//        if(!SysSecurityUtil.checkSafeAccess(req)){
//            PageJumpUtil.errorOut(ErrorResp.Block_Access, req, resp);
//            return;
//        }

        //校验请求参数
        String url = RequestUtil.getReqUrl(req);
        String[] array = StrUtil.splitToArray(url, '/');
        if(array.length != 3) {
            logger.warn(url+" 请求地址格式有误，要求:/api/{search/index}");
            PageJumpUtil.errorOut(ErrorResp.Not_Found, req, resp);
            return;
        }
//
        String api = array[2];
        switch (api){
            case "search":
                search(method, req, resp);
                break;
            case "index":
                index(method, req, resp);
                break;
            default:
                PageJumpUtil.errorOut(ErrorResp.Not_Found, req, resp);
                break;
        }
    }

    /**
     * 查询相关接口
     * @param method
     * @param req
     * @param resp
     */
    private void search(String method, HttpServletRequest req, HttpServletResponse resp){
        try {
            if(validRequest("GET", method, req, resp)){
                //校验关键字
                String query = RequestUtil.getStrParameter(req, ApiConfig.PARAM_QUERY);
                if(StrUtil.isBlank(query)){
                    PageJumpUtil.errorOut(ErrorResp.INVALID_PARAM, "query参数为空", req, resp);
                    return;
                }
                String api = RequestUtil.getStrParameter(req, ApiConfig.PARAM_API);
                String[] array = StrUtil.split(api, "/");
                String core = array[0], bizMethod = array[1];

                BaseHandler handler = ApiHandlerHelper.getHandler(core);
                if(handler == null){
                    PageJumpUtil.errorOut(ErrorResp.Not_Found, req, resp);
                    return;
                }
                handler.execute(bizMethod, req, resp);
            }
        } catch (Throwable e) {
            logger.error("search api", e);
            SysExceptionUtil.traceError("search_api", e, req);
            PageJumpUtil.errorOut(e, ErrorResp.Error, req, resp);
        }
    }

    /**
     * 变更 相关接口
     * @param method
     * @param req
     * @param resp
     */
    private void index(String method, HttpServletRequest req, HttpServletResponse resp){
        try {
            if(validRequest("POST", method, req, resp)){
                String api = RequestUtil.getStrParameter(req, ApiConfig.PARAM_API);
                String[] array = StrUtil.split(api, "/");
                String core = array[0], action = array[1];

                BaseHandler handler = ApiHandlerHelper.getHandler(core);
                if(handler == null){
                    PageJumpUtil.errorOut(ErrorResp.Not_Found, req, resp);
                    return;
                }
                handler.execute(action, req, resp);
            }
        } catch (Throwable e) {
            logger.error("index api", e);
            SysExceptionUtil.traceError("index_api", e, req);
            PageJumpUtil.errorOut(e, ErrorResp.Error, req, resp);
        }
    }

    private boolean validRequest(String defMethod, String method, HttpServletRequest req, HttpServletResponse resp){
        //验证方法
        if(!defMethod.equals(method)){
            PageJumpUtil.errorOut(ErrorResp.Not_Method_Allowed, req, resp);
            return false;
        }
        StringBuilder errorMsg = new StringBuilder();
        //验证请求
        if(!validReqInfo(req, errorMsg)){
            LogDeBugUtil.debug(errorMsg.toString());
            PageJumpUtil.errorOut(ErrorResp.INVALID_PARAM, errorMsg.toString(), req, resp);
            return false;
        }
        return true;
    }

    private boolean validReqInfo(HttpServletRequest req, StringBuilder errorMsg) {
        boolean valid = false;
        String ak = RequestUtil.getStrParameter(req, ApiConfig.PARAM_AK);
        String api = RequestUtil.getStrParameter(req, ApiConfig.PARAM_API);
        String ip = IpUtil.getRealIpAddr(req);
        if(StrUtil.isNotBlank(ak) && StrUtil.isNotBlank(api)){
            SolrClientAuth appBean = clientAuthService.getByAppKey(ak);
            if(appBean != null){
                //验证白名单
                if(validWhiteIp(ip, appBean)){
                    //验证 授权接口
                    return validAuthApi(appBean.getAuthApi(), api, errorMsg);
                }else{
                    errorMsg.append(ip + " 不是白名单IP");
                }
            }else{
                errorMsg.append("无效ak参数:" + ak);
            }
        }else{
            errorMsg.append("ak参数为空");
        }
        return valid;
    }

    private boolean validAuthApi(String authApiStr, String reqApi, StringBuilder errorMsg){
        if(StrUtil.isNotBlank(authApiStr)){
            String[] authApis = StrUtil.split(authApiStr, "|");
            for (String authApi : authApis) {
                if(reqApi.equals(authApi)){
                    return true;
                }
            }
        }
        errorMsg.append(reqApi+" 是未授权的接口");
        return false;
    }

    private boolean validWhiteIp(String ip, SolrClientAuth appBean) {
        boolean valid = false;
        //未设置白名单IP 先放行
        String whiteIpStr = appBean.getWhiteIp();
        if(StrUtil.isBlank(whiteIpStr)){
            return true;
        }
        String[] whiteIps = StrUtil.split(whiteIpStr, "|");
        for (String whiteIp : whiteIps) {
            if(ip.equals(whiteIp)){
                valid = true;
                break;
            }
        }
        return valid;
    }

}
